package haust;

import static org.lwjgl.openal.AL10.alGetError;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.lwjgl.opengl.PixelFormatLWJGL;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;

public class Entry
{	
	private static Timer tUpdate = new Timer(60);
	public static final int RENDER_NORMAL = 0;
	public static final int RENDER_3D_REDBLUE = 1;
	public static final int RENDER_3D_PASSIVE = 2;
	
	public static final int EYE_LEFT = 0;
	public static final int EYE_RIGHT = 1;
	public static float eye_seperation = 0;
	
	private static float distance = 3.0f;
	private static float sepvalue = 30.0f;
	private static float deltaTime = 0.0f;
	
	/**
	 * 
	 * @param args
	 */
	public static void main( String [] args )
	{
		Entry e = new Entry();
		
		if( e.Initialize() ) //only run if Initialize succeeds
			Entry.Run( new MainMenu() );
		
		e.Deinitialize();
	}
	
	
	/**
	 * 
	 * @param eye
	 */
	private static void setup3DFrustum(int eye)
	{
		float multiplier = 1.0f;
		if( eye == EYE_LEFT )
			multiplier = -1.0f;
		
		eye_seperation = 1.0f / sepvalue;
		float aperture = 60.0f;
		
		float ratio = Display.getWidth() / (float) Display.getHeight();
		float radians = 0.01745329251994f *  aperture / 2.0f; //DTOR * aperture / 2
		float wd2 = 0.1f * (float) Math.tan(radians); // near * tan( rad );
		float ndfl = 0.1f / distance; // near / focallength;
		
		float left = -ratio * wd2 - 0.5f*eye_seperation*ndfl*multiplier;
		float right =  ratio * wd2 - 0.5f*eye_seperation*ndfl*multiplier;
		float top = wd2;
		float bottom = -wd2;
		
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glFrustum(left,right,bottom,top,0.1f,10000.0f);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		
		eye_seperation *= -multiplier * 0.5f;
	}
	
	/**
	 * 
	 * @param c
	 */
	public static void Run(Client c)
	{
		c.Initialize();
		tUpdate.checkTime();
		
		while (!Display.isCloseRequested() && !c.getExitFlag() ) {
			if( tUpdate.checkTime() )
			{
				deltaTime = tUpdate.getDelta();
				
				c.Update(deltaTime);
				
				if( Keyboard.isKeyDown(Keyboard.KEY_UP ))distance += 5.0f * deltaTime;
				if( Keyboard.isKeyDown(Keyboard.KEY_DOWN ))distance -= 5.0f * deltaTime;
				if( Keyboard.isKeyDown(Keyboard.KEY_RIGHT ))sepvalue += 5.0f * deltaTime;
				if( Keyboard.isKeyDown(Keyboard.KEY_LEFT ))sepvalue -= 5.0f * deltaTime;
				
				if( distance < 1.0f ) distance = 1.0f;
				if( sepvalue < 0.1f ) sepvalue = 0.1f;
				
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
				glLoadIdentity();

				if( c.getRenderMode() == RENDER_NORMAL )
					c.Render();
				else
				{
					//setup left eye
					if( c.getRenderMode() == RENDER_3D_REDBLUE )
						glColorMask(true, false, false, true); //Anaglyph left eye = red color only
					else 
						glDrawBuffer( GL_BACK_LEFT );
					
					setup3DFrustum(EYE_LEFT);
					//render left eye
					c.Render();
					
					
					//setup right eye
					if( c.getRenderMode() == RENDER_3D_REDBLUE )
					{
						glClear(GL_DEPTH_BUFFER_BIT);
						glColorMask(false, true, true, true); //anaglyph right eye = cyan (green+blue) only
					}
					else
					{
						glDrawBuffer(GL_BACK_RIGHT);
						glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
					}
					
					glLoadIdentity();
					setup3DFrustum(EYE_RIGHT);

					//render right eye
					c.Render();

					//reset to normal
					glColorMask(true,true,true,true);
					glDrawBuffer(GL_BACK_LEFT);
				}

				Display.update();
			}
		}
		
		
		c.Deinitialize();
	}
	
	/**
	 * 
	 * @return
	 */
	private boolean Initialize()
	{
        try {
        	DisplayMode[] dm = Display.getAvailableDisplayModes();
        	
        	SplashScreen ss = new SplashScreen(dm);
        	
        	while( !ss.getExitFlag() ) 
        	{
        		Thread.yield();
        	}

        	ss.destroy();
        	
        	if( ss.getCancelled() )
        		return false;
        	
        	boolean passiveStereo = ss.getOption3D();
        	boolean fullscreen = ss.getFullscreen();
        	
        	PixelFormat pf = new PixelFormat().withDepthBits(24).withSamples(4).withStereo(passiveStereo).withBitsPerPixel(32);

		    Display.setDisplayMode(dm[ss.getSelectionIndex()]);
		    Display.setFullscreen(fullscreen);
		    Display.create(pf);
		    
		    AL.create();
		    alGetError(); //clear error bit
		} catch (LWJGLException e) {
		    e.printStackTrace();
		    System.exit(0);
		}
        
        glEnable(GL_DEPTH_TEST);
        
	    //set perspective
	    glMatrixMode(GL_PROJECTION);
		    glLoadIdentity();
		    gluPerspective(60, Display.getWidth() / (float) Display.getHeight(), 0.1f, 10000.0f);
		    glMatrixMode(GL_MODELVIEW);
	    glLoadIdentity();
	    
	    
	    TextureManager.Initialize();
	    FontManager.loadFont();

		return true;
	}
	
	/**
	 * 
	 */
	private void Deinitialize()
	{
		SoundManager.Destroy();
		TextureManager.Destroy();
		AL.destroy();
		Display.destroy();
	}
	
	
	/**
	 * 
	 */
	public static void pushOrtho() 
	{
	    glMatrixMode(GL_PROJECTION);
	    glPushMatrix();
	    glLoadIdentity();
	    glOrtho(0,Display.getWidth(),0,Display.getHeight(), 1, -1);
	    glMatrixMode(GL_MODELVIEW);
	    glPushMatrix();
	    glLoadIdentity();
	}
	
	/**
	 * 
	 */
	public static void popOrtho()
	{
	    glMatrixMode(GL_PROJECTION);
	    glPopMatrix();
	    glMatrixMode(GL_MODELVIEW);		
	    glPopMatrix();
	}
	

	
	/**
	 * 
	 * @return
	 */
	public static float getDelta() 
	{
		return deltaTime;
	}
}